package main

import (
	"encoding/csv"
	"fmt"
	"io"
	"log"
	"os"
	"os/exec"
	"regexp"
	"slices"
	"strings"
	"time"
	"unicode"

	"fyne.io/fyne/v2"

	"fyne.io/fyne/v2/app"
	"fyne.io/fyne/v2/container"
	"fyne.io/fyne/v2/widget"
	"github.com/flopp/go-findfont"
	"github.com/gopxl/beep/speaker"
	"github.com/gopxl/beep/wav"
	"github.com/huichen/sego"
)

var segmenter sego.Segmenter

func init() {
	//设置中文环境
	fontPaths := findfont.List()
	for _, path := range fontPaths {

		//楷体:simkai.ttf
		//黑体:simhei.ttf
		if strings.Contains(path, "simhei.ttf") {
			log.Println("设置字体路径=", path)
			os.Setenv("FYNE_FONT", path)
			break
		}
		//mac
		if strings.Contains(path, "Arial Unicode.ttf") {
			log.Println("设置字体路径=", path)
			os.Setenv("FYNE_FONT", path)
			break
		}
		//mac
		if strings.Contains(path, "Apple Braille.ttf") {
			log.Println("设置字体路径=", path)
			os.Setenv("FYNE_FONT", path)
			break
		}

	}
}

var wordsMap map[string]string
var history []string = make([]string, 0)

func loadDict() {

	file, err := os.Open("/Users/ljh/Documents/personal/keyboard_translate/wordata/EnWords.csv")
	if err != nil {
		fmt.Println("open file fail", err)
	}
	defer file.Close()

	reader := csv.NewReader(file)
	wordsMap = make(map[string]string)
	for {
		record, err := reader.Read()

		if err == io.EOF {
			break
		}
		if err != nil {
			fmt.Println("read record fail:", err)
			return
		}
		// fmt.Println(len(record))
		if len(record) == 2 {
			// fmt.Println(record[0])
			wordsMap[record[0]] = record[1]
		} else {
			fmt.Println("error record", record)
		}
	}

}
func addHistory(item string) {
	if slices.Contains(history, item) {
		return
	}
	history = append(history, item)
	if len(history) > 100 {
		history = history[1:]
	}

}

// TODO cache
// 生成文件再播放
// 按照词性的那段(字母+.)来分割 n.
var wordAttr = regexp.MustCompile("\\w+\\.")

func speakWord(word string) {
	word = strings.ReplaceAll(word, " ", "")

	text := []byte(word)
	segments := segmenter.InternalSegment(text, false)

	// 处理分词结果
	// 支持普通模式和搜索模式两种分词，见代码中SegmentsToString函数的注释。
	regresult := sego.SegmentsToSlice(segments, false)
	word = strings.Join(regresult, ". ")

	fmt.Println("play:" + word)

	// if len(splited) >= 2 {
	// 	word = splited[1]
	// }
	voice := "hak"
	voice = "cmn-latn-pinyin"
	cmd := exec.Command("espeak-ng", "-v", voice, "-s", "155", "-w", "temp.wav", `"`+word+`"`)
	out, err := cmd.CombinedOutput()
	fmt.Printf("combined out:\n%s\n", string(out))
	if err != nil {
		log.Fatalf("cmd.Run() failed with %s\n", err)
	}

	playWav("temp.wav")
}
func playWav(wavPath string) {
	f, err := os.Open(wavPath)
	if err != nil {
		log.Fatal(err)
	}
	streamer, format, err := wav.Decode(f)
	if err != nil {
		log.Fatal(err)
	}
	defer streamer.Close()

	speaker.Init(format.SampleRate, format.SampleRate.N(time.Second/10))

	// 需要调用等待的
	speaker.PlayAndWait(streamer)
	fmt.Println("played...")
}

var curString = ""

func main() {
	segmenter.LoadDictionary("segdata/dictionary.txt")
	loadDict()

	a := app.New()
	w := a.NewWindow("纯键盘无屏幕单词查询翻译器")
	w.Resize(fyne.NewSize(600, 300))
	tip := widget.NewLabel("按空格键清空，输入完成后按回车查询")
	wordLabel := widget.NewLabel("")
	resultLabel := widget.NewLabel("")
	resultLabel.Wrapping = fyne.TextWrapBreak
	historyList := widget.NewList(func() int {
		return len(history)
	}, func() fyne.CanvasObject {
		return widget.NewLabel("template")
	}, func(lii widget.ListItemID, co fyne.CanvasObject) {
		co.(*widget.Label).SetText(history[lii])
	})
	w.SetContent(
		container.NewBorder(tip, nil, nil, nil,
			container.NewHSplit(
				container.NewVBox(wordLabel, resultLabel),
				historyList),
		),
	)
	w.SetCloseIntercept(func() {
		w.Hide()
	})
	w.Canvas().SetOnTypedKey(func(ke *fyne.KeyEvent) {
		fmt.Println("type:", ke.Name, ke.Physical, ke.Physical.ScanCode)
		switch ke.Name {
		case fyne.KeySpace:
			fmt.Println("start clear")
			curString = ""
			wordLabel.SetText(curString)
			playWav("reset.wav")
		case fyne.KeyBackspace:
			curString = curString[:len(curString)-1]
			wordLabel.SetText(curString)
		case fyne.KeyReturn:

			fmt.Println("query:", curString)
			if value, ok := wordsMap[curString]; ok {
				fmt.Println("result:", value)
				resultLabel.SetText(value)
				addHistory(curString + " " + value)
				historyList.Refresh()
				words := strings.Split(value, ";")
				// 先读一遍单词
				speakWord(curString)
				for _, word := range words {

					// 按照词性分割
					splited := wordAttr.Split(word, -1)
					fmt.Println(splited)
					for _, splitWord := range splited {
						speakWord(splitWord)
						time.Sleep(500 * time.Millisecond)
					}

				}
			} else {
				playWav("not_found.wav")
				fmt.Println("word not found:", curString)
			}
		default:
			chars := []rune(ke.Name)
			if len(chars) == 1 && unicode.IsLetter(chars[0]) {
				curString = curString + strings.ToLower(string(ke.Name))
				wordLabel.SetText(curString)
			} else {
				fmt.Println("unknow key", ke.Name)

			}

		}
	})

	w.ShowAndRun()
}
